package com.zhdl.common.ytools;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 字节转换处理类
 */
public class ByteHelper {

    /**
     * DIGITAL
     */
    public static final String DIGITAL = "0123456789ABCDEF";

    /**
     * 16进制表示符
     */
    public static final String HEX = "0x";

    /**
     * 数据0
     */
    public static final byte BYTE_ZERO = 0x00;

    public static byte[] stringToBytes(String hex) {
        String hex1 = hex.replace(" ", "");
        char[] hex2char = hex1.toCharArray();
        byte[] bytes = new byte[hex1.length() / 2];

        for(int p = 0; p < bytes.length; ++p) {
            byte temp = (byte)("0123456789ABCDEF".indexOf(hex2char[2 * p]) * 16);
            temp = (byte)(temp + "0123456789ABCDEF".indexOf(hex2char[2 * p + 1]));
            bytes[p] = (byte)(temp & 255);
        }

        return bytes;
    }

    public static byte[] hexString2Bytes(String src) {
        int l = src.length() / 2;
        byte[] ret = new byte[l];

        for(int i = 0; i < l; ++i) {
            ret[i] = Integer.valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
        }

        return ret;
    }

    public static short byteArrayToShortLow(byte[] bytes) throws Exception {
        if (bytes.length != 2) {
            throw new Exception("长度不正确");
        } else {
            return (short)(bytes[0] & 255 | (bytes[1] & 255) << 8);
        }
    }

    /**
     * 左补0功能
     *
     * @param val
     * @param totalLen
     * @return
     */
    public static String padZeroLeft(int val, int totalLen) {
        return String.format("%0" + totalLen + "d", val);
    }

    /**
     * 字节数组转16进制字符串 0x1234转换为字符串1234
     *
     * @param b 字节数组
     * @return 16进制字符串
     */
    public static String byteToString(byte b) {
        StringBuilder sbf = new StringBuilder();
        String hex = Integer.toHexString(b);
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        sbf.append(hex.toUpperCase()).append(" ");
        return sbf.toString().trim();
    }

    /**
     * 字节数组转16进制字符串 0x1234转换为字符串1234
     *
     * @param b 字节数组
     * @return 16进制字符串
     */
    public static String byteToString(byte[] b) {
        StringBuilder sbf = new StringBuilder();
        for (byte value : b) {
            String hex = Integer.toHexString(value & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sbf.append(hex.toUpperCase()).append(" ");
        }
        return sbf.toString().trim();
    }

    /**
     * 16进制字符串转字节数组 字符串1234转换为0x1234
     *
     * @param hex 16进制字符串
     * @return 字节数组
     */
    public static byte[] hex2byte(String hex) {
        hex = hex.replace(" ", "");

        if (!isHexString(hex))
            return null;

        char[] arr = hex.toCharArray();
        byte[] b = new byte[hex.length() / 2];
        for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
            String swap = "" + arr[i++] + arr[i];
            int byteint = Integer.parseInt(swap, 16) & 0xFF;
            b[j] = Integer.valueOf(byteint).byteValue();
        }
        return b;
    }

    /**
     * 校验是否是16进制字符串
     *
     * @param hex
     * @return
     */
    public static boolean isHexString(String hex) {
        if (hex == null || hex.length() % 2 != 0) {
            return false;
        }
        for (int i = 0; i < hex.length(); i++) {
            char c = hex.charAt(i);
            if (!isHexChar(c)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 校验是否是16进制字符
     *
     * @param c
     * @return
     */
    private static boolean isHexChar(char c) {
        return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
    }

    /**
     * 将short转为低字节在前，高字节在后的byte数组
     */
    public static byte[] shortToByteArrayByLow(short n) {
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (n & 0xff);
        bytes[1] = (byte) (n >>> 8 & 0xff);
        return bytes;
    }

    /**
     * 将short转为高字节在前，低字节在后的byte数组
     */
    public static byte[] shortToByteArrayByHigh(short n) {
        byte[] bytes = new byte[2];
        bytes[1] = (byte) (n & 0xff);
        bytes[0] = (byte) (n >>> 8 & 0xff);
        return bytes;
    }

    /**
     * byte数组转换为有符号short，低字节在前
     *
     * @param bytes 2字节数组
     * @return 有符号short
     */
    public static short byteArrayToShortLittle(byte[] bytes) {
        // 创建字节缓冲区
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        // 设置为小端序
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        // 获取该字节缓冲区对应的 short 值
        return buffer.getShort();
    }

    /**
     * byte数组转换为short，高字节在前，低字节在后
     *
     * @param bytes 2字节数组
     * @return 有符号short
     */
    public static short byteArrayToShortBig(byte[] bytes) {
        // 创建字节缓冲区
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        // 设置为小端序
        buffer.order(ByteOrder.BIG_ENDIAN);
        // 获取该字节缓冲区对应的 short 值
        return buffer.getShort();
    }

    public static int byteArrayToIntLittle(byte[] bytes) {
        byte[] newBs = new byte[4];
        if (bytes.length > 4) throw new RuntimeException("bytes length不能超过4");

        for (int i = 0; i < bytes.length; i++)
            newBs[i] = bytes[i];

        // 创建字节缓冲区
        ByteBuffer buffer = ByteBuffer.wrap(newBs);
        // 设置为小端序
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        // 获取该字节缓冲区对应的 short 值
        return buffer.getInt();
    }


    public static byte[] byteListToByteArray(List<Byte> list) {
        byte[] bytes = new byte[list.size()];
        for (int i = 0; i < list.size(); i++)
            bytes[i] = list.get(i);

        return bytes;
    }

    /**
     * byte数组转换为float，大端模式,高位字节在前，低位字节在后
     *
     * @param bytes 2字节数组
     * @return 有符号short
     */
    public static float byteArrayToFloatBigEndian(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        buffer.order(ByteOrder.BIG_ENDIAN); // 指定为 Big-Endian 字节序

        return buffer.getFloat();
    }

    /**
     * byte数组转换为float，小端模式，低字节在前，高字节在后
     *
     * @param bytes 2字节数组
     * @return 有符号short
     */
    public static float byteArrayToFloatLittleEndian(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        buffer.order(ByteOrder.LITTLE_ENDIAN); // 指定为 Big-Endian 字节序

        return buffer.getFloat();
    }

    /**
     * 无符号int转换为byte[]，不考虑正负
     *
     * @param i
     * @return
     */
    public static byte[] uIntToByteArray(long i) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) i;
        bytes[1] = (byte) (i >> 8);
        bytes[2] = (byte) (i >> 16);
        bytes[3] = (byte) (i >> 24);
        return bytes;
    }

    /**
     * U16转换为2字节 byte[],低字节在前
     *
     * @param unsignedShort 无符号U16
     * @return
     */
    public static byte[] u16ToByteArrayLow(int unsignedShort) {
        byte[] bytes = new byte[2];
        bytes[1] = (byte) ((unsignedShort >> 8) & 0xFF);
        bytes[0] = (byte) (unsignedShort & 0xFF);
        return bytes;
    }

    /**
     * 字节数组转换为无符号int
     *
     * @param bytes bytes
     * @return long
     */
    public static long byteArrayToUInt(byte[] bytes) {
        long res = 0;
        for (int i = 0; i < bytes.length; i++)
            res += (bytes[i] & 0xff) << i * 8;

        return res;
    }


    /**
     * 有符号int转换为byte[]
     *
     * @param i
     * @return
     */
    public static byte[] IntToByteArray(long i) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (i & 0xff);
        bytes[1] = (byte) (i >> 8 & 0xff);
        bytes[2] = (byte) (i >> 16 & 0xff);
        bytes[3] = (byte) (i >> 24 & 0xff);
        return bytes;
    }

    /**
     * 4字节数组byte[]转换为int，带符号
     *
     * @param bytes 4字节数组
     * @return
     */
    public static int byteArrayToInt(byte[] bytes) {
        return (bytes[0] & 0xff)
                + ((bytes[1] & 0xff) << 8)
                + ((bytes[2] & 0xff) << 16)
                + ((bytes[3] & 0xff) << 24);
    }

    /**
     * int转换为byte[]，不考虑正负，采用逆序转储
     *
     * @param i
     * @return
     */
    public static byte[] intToByteArrayReverse(int i) {
        byte[] b = new byte[4];
        b[0] = (byte) (i >> 24);
        b[1] = (byte) (i >> 16);
        b[2] = (byte) (i >> 8);
        b[3] = (byte) i;
        return b;
    }

    public static int byteArrayToIntReverse(byte[] bytes) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            value += (bytes[i] & 0xff) << (3 - i) * 8;
        }
        return value;
    }


    /**
     * 字节数组转换为16进制字符串
     *
     * @param src src
     * @return string string
     */
    public static String bytesArrayToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (byte b : src) {
            int v = b & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 二进制字符串转字节，00000000 返回0x00
     *
     * @param bitStr
     * @return
     */
    public static byte bitString2Byte(String bitStr) {
        if (bitStr == null || bitStr.length() == 0) return 0;
        if (bitStr.length() != 8) {
            // 如果不足8位的，补足8位;超过8位，截取后8位
            String temp = ("00000000" + bitStr);
            bitStr = temp.substring(temp.length() - 8, 8);
        }

        byte rs;
        if (bitStr.charAt(0) == '0') {
            // 正数
            rs = Byte.parseByte(bitStr, 2);
        } else {
            // 负数
            rs = (byte) (Integer.parseInt(bitStr, 2) - 256);
        }

        return rs;
    }

    /**
     * 字转转换为二进制字符串 0x64转换为01100100
     *
     * @param bt
     * @return
     */
    public static String byte2BitString(byte bt) {
        StringBuilder sb = new StringBuilder();
        sb.append((bt >> 7) & 0x1);
        sb.append((bt >> 6) & 0x1);
        sb.append((bt >> 5) & 0x1);
        sb.append((bt >> 4) & 0x1);
        sb.append((bt >> 3) & 0x1);
        sb.append((bt >> 2) & 0x1);
        sb.append((bt >> 1) & 0x1);
        sb.append((bt) & 0x1);
        return sb.toString();
    }

    /**
     * 字转转换为二进制字符串 0x0102 转换为 0000000100000010
     *
     * @param bs
     * @return
     */
    public static String byte2BitString(byte[] bs) {
        StringBuilder sb = new StringBuilder();
        for (byte bt : bs) {
            sb.append((bt >> 7) & 0x1);
            sb.append((bt >> 6) & 0x1);
            sb.append((bt >> 5) & 0x1);
            sb.append((bt >> 4) & 0x1);
            sb.append((bt >> 3) & 0x1);
            sb.append((bt >> 2) & 0x1);
            sb.append((bt >> 1) & 0x1);
            sb.append((bt) & 0x1);
        }
        return sb.toString();
    }

    /**
     * 字转转换 0x03转换为00000011，输出为[false, false, false, false, false, false, true, true]
     *
     * @param bt
     * @return
     */
    public static boolean[] byte2Boolean(byte bt) {
        boolean[] out = new boolean[8];
        String str = byte2BitString(bt);
        for (int i = 0; i < str.length(); i++)
            out[i] = str.charAt(i) == '1';

        return out;
    }

    /**
     * 字转转换  0x0102 转换为 0000000100000010，
     * 输出为 [false, false, false, false, false, false, false, true, false, false, false, false, false, false, true, false]
     *
     * @param bt
     * @return
     */
    public static boolean[] byte2Boolean(byte[] bt) {
        boolean[] out = new boolean[bt.length * 8];
        String str = byte2BitString(bt);
        for (int i = 0; i < str.length(); i++)
            out[i] = str.charAt(i) == '1';

        return out;
    }

    /**
     * 字转转换 0x03转换为00000011，输出为[1, 1, 0, 0, 0, 0, 0, 0]
     * 二进制最右侧为bit0，所以将最右侧的bit0放在index=0的位置
     *
     * @param bt
     * @return
     */
    public static byte[] byte2NumList(byte bt) {
        byte[] out = new byte[8];
        out[7] = (byte) ((bt >> 7) & 0x1);
        out[6] = (byte) ((bt >> 6) & 0x1);
        out[5] = (byte) ((bt >> 5) & 0x1);
        out[4] = (byte) ((bt >> 4) & 0x1);
        out[3] = (byte) ((bt >> 3) & 0x1);
        out[2] = (byte) ((bt >> 2) & 0x1);
        out[1] = (byte) ((bt >> 1) & 0x1);
        out[0] = (byte) ((bt) & 0x1);
        return out;
    }

    /**
     * 字转转换 {0x01, 0x03}转换为00000001 00000011，输出为[1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0]
     * 二进制最右侧为bit0，所以将最右侧的bit0放在index=0的位置
     *
     * @param bs
     * @return
     */
    public static byte[] byte2NumList(byte[] bs) {
        byte[] out = new byte[bs.length * 8];
        for (int i = 0; i < bs.length; i++) {
            byte bt = bs[i];
            out[7 + i * 8] = (byte) ((bt >> 7) & 0x1);
            out[6 + i * 8] = (byte) ((bt >> 6) & 0x1);
            out[5 + i * 8] = (byte) ((bt >> 5) & 0x1);
            out[4 + i * 8] = (byte) ((bt >> 4) & 0x1);
            out[3 + i * 8] = (byte) ((bt >> 3) & 0x1);
            out[2 + i * 8] = (byte) ((bt >> 2) & 0x1);
            out[1 + i * 8] = (byte) ((bt >> 1) & 0x1);
            out[0 + i * 8] = (byte) ((bt) & 0x1);
        }
        return out;
    }

    /**
     * 求和
     *
     * @param bs 待计算的数组
     * @return 校验和字节
     */
    public static byte sumBytes(byte[] bs) {
        long sumValue = 0;
        for (byte bt : bs) {
            sumValue += bt;
        }
        return (byte) (sumValue & 0xff);
    }

    /**
     * 使用 short 类型（16 位）来模拟无符号 byte (0 到 255 )
     * 比如输入short = 255，正常是无法用byte来表示的，这个方法输出0xFF，看似是-1，实则为255
     *
     * @param value short 类型（16 位）
     * @return byte
     */
    public static byte UByte(short value) {
        if (value < 0) throw new RuntimeException("值不能小于0:value=" + value);
        if (value > 255) throw new RuntimeException("值不能大于255:value=" + value);
        return (byte) (value & 0xFF);
    }

    /**
     * 使用 int 类型（32 位）来模拟无符号 byte
     *
     * @param value int 类型（32 位）
     * @return 0 到 255 范围内的无符号 byte 值
     */
    public static byte UByte(int value) {
        return UByte((short) value);
    }

    /**
     * 使用 short 类型（16 位）来模拟无符号 byte (0 到 255 )
     *
     * @param value short 类型（16 位）
     * @return 0 到 255 范围内的无符号 short 值
     */
    public static short UByteToShort(byte value) {
        byte[] bs = new byte[2];
        bs[0] = value;
        return byteArrayToShortLittle(bs);
    }

    /**
     * 使用 int 类型（32 位）来模拟无符号 byte (0 到 255 )
     *
     * @param value byte
     * @return int
     */
    public static int UByteToInt(byte value) {
        return UByteToShort(value);
    }

    /**
     * 将byte[]转换为ASCII字符串，比如将  0x31 0x32 转换为 12
     *
     * @param bs bs
     * @return text
     */
    public static String bytesToAscii(byte[] bs) {
        // 使用“UTF-8”编码从字节数组创建一个字符串
        return new String(bs, StandardCharsets.UTF_8);
    }

    /**
     * 将byte[]转换为ASCII字符串，比如将  0x31 转换为 1
     *
     * @param bt bt
     * @return text
     */
    public static String bytesToAscii(byte bt) {
        // 使用“UTF-8”编码从字节数组创建一个字符串
        return new String(new byte[]{bt}, StandardCharsets.UTF_8);
    }

    /**
     * 将ASCII字符串转换为byte[]，比如将 1234 转换为 0x31 0x32 0x33 0x34
     *
     * @param text ASCII字符串
     * @return byte[]
     */
    public static byte[] asciiToBytes(String text) {
        return text.getBytes(StandardCharsets.UTF_8);
    }

    /**
     * 将ArrayList<Byte>转换为byte[]
     *
     * @param byteList ArrayList<Byte>
     * @return byte[]
     */
    public static byte[] arrayListByteToArray(ArrayList<Byte> byteList) {
        // 将ArrayList<Byte>转换为byte[]
        byte[] byteArray = new byte[byteList.size()];
        for (int i = 0; i < byteList.size(); i++) {
            byteArray[i] = byteList.get(i);
        }
        return byteArray;
    }

}
